// XMLParser.java
// Author: Jim Sproch
// Created: April 29, 2006
// Modified: February 20, 2008
// Part of the Aforce Port
// Mac < Windows < Linux

/**
	XMLParser parses an XML file and creates objects!
	@author Jim Sproch
	@version 0.1a beta
*/

import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;

import org.xml.sax.XMLReader;

import org.xml.sax.helpers.DefaultHandler;	//Used in XMLContentHandler
import org.xml.sax.Attributes;			//Used in XMLContentHandler
import java.util.*;				//Used in XMLContentHandler

public class XMLParser
{
	private XMLContentHandler xmlHandler = new XMLContentHandler();

	public XMLParser(String filename)
	{
		try
		{
			SAXParserFactory factory = SAXParserFactory.newInstance();
			SAXParser saxParser = factory.newSAXParser();
			XMLReader xmlReader = saxParser.getXMLReader();
	
			xmlReader.setContentHandler(xmlHandler);
			xmlReader.parse(XMLParser.class.getResource(filename).toString());
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	public DisplayableObject getDisplayableObject()
	{
		return xmlHandler.getDisplayableObject();
	}
}


class XMLContentHandler extends DefaultHandler
{
	private HashMap<String, XMLAttributes> objectTypes = new HashMap<String, XMLAttributes>();
	private ArrayList<DisplayableObject> objects = new ArrayList<DisplayableObject>();

	public DisplayableObject getDisplayableObject()
	{
		if(objects.size() < 1) return null;
		DisplayableObject result = objects.get(0);
		objects.remove(0);
		return result;
	}

	// ***********************************************
	// ****** Methods for handleing XML Parsing ******
	// ***********************************************

	// Parser calls this method when it starts parsing.
	public void startDocument()
	{
		Printer.xml.println("Starting document...");
	}

	// This method gets called every time the parser encounters a start tag in the XML file.
	public void startElement(String url, String localName, String qualName, Attributes attribs) {

		if("ObstacleType".equals(qualName))
		{
			objectTypes.put(attribs.getValue("id"), new XMLAttributes(attribs));
		}

		if("UnitType".equals(qualName))
		{
			objectTypes.put(attribs.getValue("id"), new XMLAttributes(attribs));
		}

		if("Obstacle".equals(qualName))
		{
			XMLAttributes masterAttribs = objectTypes.get(attribs.getValue("type"));
			Picture picture = Images.getPicture(masterAttribs.getValue("picture"));
			Size size = new Size(Integer.parseInt(masterAttribs.getValue("xsize")), Integer.parseInt(masterAttribs.getValue("ysize")));
			Location location = new Location(Integer.parseInt(attribs.getValue("xlocation")), Integer.parseInt(attribs.getValue("ylocation")));

			Block obstacle = new Block(picture, size, location);
			objects.add(obstacle);
		}


		if("Unit".equals(qualName))
		{
			XMLAttributes attributes = XMLAttributes.combine(objectTypes.get(attribs.getValue("type")), attribs);
			Picture picture = Images.getPicture(attributes.getValue("picture"));
			Size size = new Size(Integer.parseInt(attributes.getValue("xsize")), Integer.parseInt(attributes.getValue("ysize")), Integer.parseInt(attributes.getValue("xoffset")), Integer.parseInt(attributes.getValue("yoffset")));
			Location location = new Location(Integer.parseInt(attributes.getValue("xlocation")), Integer.parseInt(attributes.getValue("ylocation")));
			int direction = Direction.toInt(attributes.getValue("direction"));
			int team = Integer.parseInt(attributes.getValue("team"));

			Ship ship = new Ship(picture, size, location, direction, team);


			try
			{	// This will fail (and autopilot will not be set) if autopilot is not set in xml file
				int autopilot = Integer.parseInt(attributes.getValue("autopilot"));
				ship.autopilot(autopilot);
			}
			catch(Exception e){}
			if("true".equals(attributes.getValue("usership"))) ship.setUserShip();
			objects.add(ship);
		}
	}

	// This method gets called one or more times(depending on parser being used) whenever data is
	// encountered between a start tag and its ending tag.
	public void characters (char[] charArray, int start, int length)
	{
		return;
	}

	// Gets called when an end tag is encountered.
	public void endElement(String url, String localName, String qualName)
	{
		return;
	}

	public void endDocument()
	{
		Printer.xml.println("End of document.");
	}
}




class XMLAttributes implements Attributes
{
	HashMap<String, String> attributeMap = new HashMap<String, String>();
	ArrayList<String> keys = new ArrayList<String>();

	XMLAttributes(Attributes attributes)
	{
		add(attributes);
	}

	public String getValue(String key)
	{
		return attributeMap.get(key);
	}

	public void add(Attributes attributes)
	{
		for (int idx=0; idx < attributes.getLength(); ++idx)
		{
			if(!keys.contains(attributes.getQName(idx))) keys.add(attributes.getQName(idx));
			attributeMap.put(attributes.getQName(idx), attributes.getValue(idx));
		}
	}

	public static XMLAttributes combine(Attributes a1, Attributes a2)
	{
		XMLAttributes mix = new XMLAttributes(a1);
		mix.add(a2);
		return mix;
	}

	public int getLength()
	{
		return attributeMap.size();
	}

	public String getQName(int idx)
	{
		return keys.get(idx);
	}

	public String getValue(int idx)
	{
		return attributeMap.get(keys.get(idx));
	}

	public int getIndex(String key)
	{
		return keys.lastIndexOf(key);
	}

	public String getType(int index)
	{
		// All types are strings
		return "String";
	}

	public String getValue(String s1, String s2)
	{
		// I am not sure what this method does (and I am no using it), so this is just a dummy
		//  I need it because XMLAttributes implements Attributes
		return "";
	}
	public String getType(String s1, String s2)
	{
		// I am not sure what this method does (and I am no using it), so this is just a dummy
		//  I need it because XMLAttributes implements Attributes
		return "";
	}
	public int getIndex(String s1, String s2)
	{
		// I am not sure what this method does (and I am no using it), so this is just a dummy
		//  I need it because XMLAttributes implements Attributes
		return 0;
	}
	public String getType(String s1)
	{
		// I am not sure what this method does (and I am no using it), so this is just a dummy
		//  I need it because XMLAttributes implements Attributes
		return "";
	}
	public String getLocalName(int i1)
	{
		// I am not sure what this method does (and I am no using it), so this is just a dummy
		//  I need it because XMLAttributes implements Attributes
		return "";
	}
	public String getURI(int i1)
	{
		// I am not sure what this method does (and I am no using it), so this is just a dummy
		//  I need it because XMLAttributes implements Attributes
		return "";
	}

	public static void main(String[] args)
	{
		Printer.noexecute();
	}
}